﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text;

using Microsoft.CSharp;

namespace CssAndJsCombiner
{
    public class SimpleTextParser
    {
        private StringDictionary _variables = new StringDictionary();
        public StringDictionary Variables
        {
            get { return this._variables; }
        }

        public string ParseContent(string content)
        {
            StringBuilder sb = new StringBuilder();

            using (TextReader reader = new StringReader(content))
            {
                while (reader.Peek() > -1)
                {
                    string line = reader.ReadLine();
                    if (line.StartsWith("#define "))
                    {
                        line = line.Replace("#define ", String.Empty);
                        int index = line.IndexOf("=") + 1;
                        string key = line.Substring(0, index - 1).Trim();
                        string value = line.Substring(index, line.Length - index).Replace(";", String.Empty).Trim();

                        foreach (string var in Variables.Keys)
                        {
                            if (value.Contains(var))
                                value = value.Replace(var, Variables[var]);
                        }

                        value = ProcessExpression(value);
                        Variables.Add(key, value);
                    }
                    else
                    {
                        sb.AppendLine(line);
                    }
                }
            }

            foreach (string variable in Variables.Keys)
            {
                sb.Replace(variable, Variables[variable]);
            }

            return sb.ToString();
        }

        private string ProcessExpression(string expression)
        {
            if (expression.Contains("System."))
                throw new ArgumentException("Command is not allowed: " + expression);

            using (CSharpCodeProvider provider = new CSharpCodeProvider())
            {
                CompilerParameters parameters = new CompilerParameters();
                parameters.GenerateExecutable = false;
                parameters.GenerateInMemory = true;

                string source = "namespace CssAndJsCombiner {" +
                                "class parser {" +
                                "public static object Evaluate() { return " + expression + "; }}} ";

                CompilerResults result = provider.CompileAssemblyFromSource(parameters, source);

                if (result.Errors.Count > 0)
                {
                    return expression;
                }
                else
                {
                    MethodInfo Methinfo = result.CompiledAssembly.GetType("CssAndJsCombiner.parser").GetMethod("Evaluate");
                    return Methinfo.Invoke(null, null).ToString();
                }
            }
        }
    }
}
